/* Format.cpp
Michael Zahniser, 12/12/09

Function definitions for the Format class.
*/

#include "Format.h"

#include <limits>

using std::string;



double Format::Read(const string &text, int base)
{
	// Check for base prefixes.
	if(text.length() >= 2 && text[0] == '0')
	{
		if(text[1] == 'x')
			return Read(text.substr(2), 16);
		if(text[1] == 'd')
			return Read(text.substr(2), 10);
		if(text[1] == 'o')
			return Read(text.substr(2), 8);
		if(text[1] == 'b')
			return Read(text.substr(2), 2);
	}
	
	string::const_iterator it = text.begin();

	// Check for a negative sign.
	long long divisor = 1;
	if(*it == '-')
	{
		divisor = -1;
		++it;
	}
	
	int shift = 1;
	long long value = 0;
	
	for( ; it != text.end(); ++it)
	{
		if(*it == '.')
			shift = base;
		else
		{
			value *= base;
			divisor *= shift;
		
			int digit = Value(*it);
			if(digit >= base)
				return std::numeric_limits<double>::quiet_NaN();
			value += digit;
		}
	}
	
	return static_cast<double>(value) / static_cast<double>(divisor);
}



string Format::Write(double value, int base)
{
	bool isNegative = (value < 0);
	if(isNegative)
		value = -value;
	
	string text;

	long long i;
	Round(i, value);
	if(!i && !value)
		return "0";
	while(i)
	{
		text = Digit(i % base) + text;
		i /= base;
	}
	
	if(value)
	{
		text += '.';
		
		do {
			value *= base;
			Round(i, value);
			text += Digit(i % base);
		} while(value && text.length() < 17);
	}
	
	if(isNegative)
		text = '-' + text;
	return text;
}



int Format::Value(char c)
{
	if(c >= '0' && c <= '9')
		return c - '0';
	if(c >= 'a' && c <= 'z')
		c += 'A' - 'a';
	if(c < 'A')
		return 255;
	return c - ('A' - 10);
}



char Format::Digit(int n)
{
	if(n < 10)
		return n + '0';
	return n + ('A' - 10);
}



void Format::Round(long long &i, double &f)
{
	i = static_cast<long long>(f);
	f -= static_cast<double>(i);
	
	static const double eps = .000001;
	if(f > 1. - eps)
	{
		++i;
		f = 0.;
	}
	else if(f < eps)
		f = 0.;
}
